package com.yirui.bridge.udp;

import com.yirui.bridge.core.Server;
import com.yirui.bridge.util.HexCodec;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.context.annotation.Bean;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 接收节点推送数据服务
 * @author Dujie
 * @create 2021/9/28
 * @since 1.0.0
 */
@Slf4j
public class NettyUdpClient implements Server {


    private Map<String, Object> res = new HashMap();
    private String host;
    private int port;
    private byte[] sessionId;
    private AtomicBoolean receiveData = new AtomicBoolean();
    public void put(String key, Object item){
        res.put(key, item);
    }


    private EventLoopGroup eventLoopGroup;
    //监听端口的通道，即server的处理通道
    private Channel channel;
    private ChannelInitializer<NioDatagramChannel> channelInitializer;

    public void setEventLoopGroup(EventLoopGroup eventLoopGroup) {
        this.eventLoopGroup = eventLoopGroup;
    }

    public void setChannelInitializer(ChannelInitializer<NioDatagramChannel> channelInitializer) {
        this.channelInitializer = channelInitializer;
    }

    public void stop() {
        log.debug("UdpClient server stop.");
        try {
            if (channel != null) {
                ChannelFuture await = channel.close().await();
                if (!await.isSuccess()) {
                    log.error("udp channel close fail, {}", await.cause());
                }
            }
            Future<?> future1 = eventLoopGroup.shutdownGracefully().await();
            if (!future1.isSuccess()) {
                log.error("udp group shutdown fail, {}", future1.cause());
            }
            log.info("UdpClient shutdown success");
        } catch (InterruptedException e) {
            log.info("UdpClient shutdown fail {}", e.getMessage());
        }
    }

    private ChannelFuture start() {
        log.debug("UdpClient server start.");
        //启动类
        Bootstrap serverBootstrap = new Bootstrap();
        //组配置，初始化ServerBootstrap的线程组
        serverBootstrap.group(eventLoopGroup)
                //数据包通道，udp通道类型
                .channel(NioDatagramChannel.class)
                //支持广播
                .option(ChannelOption.SO_BROADCAST, true)
                //接收包缓存
                .option(ChannelOption.SO_RCVBUF, 512)
                //通道处理者
                .handler(channelInitializer);
        //Future：异步任务的生命周期，可用来获取任务结果
        //绑定端口，开启监听,同步等待

        ChannelFuture channelFuture1 = serverBootstrap.bind(port).syncUninterruptibly();
        if (channelFuture1 != null && channelFuture1.isSuccess()) {
            //log.info("[UdpClient] server start success, port = 12345");
            log.info("[UdpClient] server start success, port = {}", port);
            //获取通道
            channel = channelFuture1.channel();
        } else {
            log.error("UdpClient server start failed!!");
            channelFuture1.cause().printStackTrace();
        }
        return channelFuture1;
    }

    public void send(DatagramPacket datagramPacket){
        if(channel!=null) {
            channel.writeAndFlush(datagramPacket).addListener(new GenericFutureListener<ChannelFuture>() {
                @Override
                public void operationComplete(ChannelFuture future)
                        throws Exception {
                    boolean success = future.isSuccess();
                    log.info("Sender datagramPacket result : " + success);
                }
            });
        }

    }

    public String getHost() {
        return host;
    }

    public int getPort() {
        return port;
    }

    public Map<String, Object> getRes() {
        return res;
    }

    public AtomicBoolean getReceiveData() {
        return receiveData;
    }

    public DatagramPacket createPacket(byte[] buffer, String host, int port){
        return new DatagramPacket(Unpooled.copiedBuffer(buffer), new InetSocketAddress(host,port));
    }

    public void send(byte[] buffer){
        log.debug("向目标地址:{}:{}发送数据包:{}",getHost(), getPort(), HexCodec.decode(buffer, ' '));
        send(createPacket(buffer, getHost(), getPort()));
    }

    public Channel getChannel() {
        return channel;
    }


    public UdpChannelInboundHandler udpChannelInboundHandler(){
        return new UdpChannelInboundHandler(this);
    }

    public ChannelInitializer<NioDatagramChannel> channelInitializer(UdpChannelInboundHandler udpChannelInboundHandler){
        //通道初始化，主要Handler注册
        return new ChannelInitializer<NioDatagramChannel>(){

            @Override
            protected void initChannel(NioDatagramChannel nioDatagramChannel) throws Exception {
                ChannelPipeline pipeline = nioDatagramChannel.pipeline();
                pipeline.addLast("receive", udpChannelInboundHandler);
            }
        };

    }

    @Override
    public void start(String host, int port, ApplicationArguments args) throws Exception {
        this.host = host;
        this.port = port;

        setChannelInitializer(channelInitializer(udpChannelInboundHandler()));
        setEventLoopGroup(new NioEventLoopGroup(1));

        start();
        if(args.containsOption("sid")){
            String sid = args.getOptionValues("sid").get(0);
            this.sessionId = HexCodec.encode(sid);

            send(sessionId);

//                    new Timer().scheduleAtFixedRate(new TimerTask() {
//                        @Override
//                        public void run() {
//                            if(!udpClientStatus.isReceiveData()) {
//                                nettyUdpClient.send(udpClientStatus.getSessionId());
//                            }
//                        }
//                    },1000,30000);
        }
        //默认指令
        if(args.containsOption("cmd")){
            String tm= args.getOptionValues("cmd").get(0);
            send(HexCodec.encode(tm));
        }

    }

    public byte[] getSessionId() {
        return sessionId;
    }
}
